import logging
import uuid

from repoze.who.interfaces import IAuthenticator
from repoze.who.interfaces import IMetadataProvider
from zope.interface import implements
from omero import client_wrapper
from paste.request import get_cookies

omero_sessions = {}


class OMEROAuthenticatorPlugin:
    implements(IAuthenticator)

    def __init__(self, host, port, cookie_name, cookie_path='/'):
        # statement should be pyformat dbapi binding-style, e.g.
        # "select user_id, password from users where login=%(login)s"
        self.host = host
        self.port = port
        self.cookie_name = cookie_name
        self.cookie_path = cookie_path

    # IAuthenticator
    def authenticate(self, environ, identity):
        if not 'login' in identity:
            return None
        blitzcon = client_wrapper(identity['login'], identity['password'],
                                  host=self.host, port=int(self.port))

        if blitzcon.connect():
            environ['ampersands.omero'] = blitzcon
            return identity['login']

    # IIdentifier
    def identify(self, environ):
        cookies = get_cookies(environ)
        cookie = cookies.get(self.cookie_name)
        if cookie is None or not cookie.value:
            return None
        if not cookie.value in omero_sessions:
            return None
        c = omero_sessions[cookie.value]
        if not c.isConnected():
            return None
        environ['ampersands.omero'] = c

        identity = {}
        identity['repoze.who.userid'] = c._user.getName()
        return identity

    # IIdentifier
    def forget(self, environ, identity):
        cookies = get_cookies(environ)
        # return a expires Set-Cookie header
        expired = ('%s=""; Path=%s; Expires=Sun, 10-May-1971 11:59:00 GMT' %
                   (self.cookie_name, self.cookie_path))
        existing = cookies.get(self.cookie_name)
        omero_sessions[existing.value].seppuku()
        del omero_sessions[existing.value]
        return [('Set-Cookie', expired)]

    # IIdentifier
    def remember(self, environ, identity):
        cookie_value = str(uuid.uuid4())
        cookie_value = cookie_value.encode('base64').rstrip()
        cookies = get_cookies(environ)
        existing = cookies.get(self.cookie_name)
        value = getattr(existing, 'value', None)

        if value != cookie_value:
            # return a Set-Cookie header
            omero_sessions[cookie_value] = environ['ampersands.omero']
            set_cookie = '%s=%s; Path=%s;' % (self.cookie_name, cookie_value,
                                              self.cookie_path)
            return [('Set-Cookie', set_cookie)]


def make_authenticator_plugin(host=None, port=None,
                              cookie_name=None,
                              cookie_path='/', **kw):
    if host is None:
        raise ValueError('host must be specified')
    if port is None:
        raise ValueError('port must be specified')
    if cookie_name is None:
        raise ValueError('cookie_name must be specified')
    if cookie_path is None:
        raise ValueError('cookied_path must be specified')
    return OMEROAuthenticatorPlugin(host, port, cookie_name, cookie_path)


class OMEROMetadataProviderPlugin:
    implements(IMetadataProvider)

    def __init__(self, name):
        self.name = name

    # IMetadataProvider
    def add_metadata(self, environ, identity):
        blitzcon = environ['ampersands.omero']
        me = blitzcon.getUser()
        identity[self.name] = {"display": me.getFullName()}


def make_metadata_plugin(name=None, **kw):
    if name is None:
        raise ValueError('name must be specified')
    return OMEROMetadataProviderPlugin(name)
